<style lang="scss">
	.hqs-popup {
		.qs-con {
			background: #fff;
		}

		.qs-header {
			display: flex;
			align-items: center;
			justify-content: space-between;
			position: relative;
		}

		.qs-title {
			font-size: 16px;
			font-weight: bold;
			overflow: hidden;
			white-space: nowrap;
			text-overflow: ellipsis;
		}

		.hidden {
			visibility: hidden;
		}

		.qs-side {
			min-width: 60px;
			padding: 15px 20px;
			color: #888;
			flex-shrink: 0;

			&:active {
				opacity: .8;
			}
		}

		.qs-h-scroll {
			height: 100vh;
			// #ifdef H5
			margin-top: 44px;
			height: calc(100vh - 44px);
			// #endif
		}

		.ta-r {
			text-align: right;
		}
	}
</style>

<template>
	<uni-popup ref="popup" :mask-click="maskClick" @change="onChange" :type="from" class="hqs-popup">
		<view class="qs-con" :style="conStyle" @mousedown="onTouch" @mousemove="onTouch" @mouseup="onTouch"
			@touchstart="onTouch" @touchmove="onTouch" @touchend="onTouch">
			<block v-if="isVertical">
				<view class="qs-header" v-if="from == 'bottom' && showHeader">
					<view class="qs-side" :class="{'hidden': !showBack && !$slots.back}" @click="onBack">
						<slot name="back">
							<text>返回</text>
						</slot>
					</view>
					<slot name="title">
						<text class="qs-title">{{ title }}</text>
					</slot>
					<view class="qs-side ta-r" :class="{'hidden': !showClose}" @click="close">
						<slot name="close">
							<u-icon :name="closeIcon" :size="32" v-if="closeIcon"></u-icon>
							<text v-else>关闭</text>
						</slot>
					</view>
				</view>
				<slot name="sub-header"></slot>
				<scroll-view scroll-y :style="{ height }" @scroll="onScroll">
					<view>
						<slot></slot>
					</view>
				</scroll-view>
				<slot name="bottom"></slot>
			</block>
			<block v-else-if="!isVertical">
				<scroll-view scroll-y class="qs-h-scroll" :style="{ width }">
					<slot></slot>
				</scroll-view>
			</block>
		</view>
	</uni-popup>
</template>

<script>
	import UniPopup from './uni-popup.vue'

	export default {
		components: {
			UniPopup,
		},
		props: {
			// 弹窗显示可通过v-model控制
			value: Boolean,

			// 弹窗打开开始方向
			from: {
				type: String,
				default: 'bottom',
			},

			// 内容区边缘圆角大小
			round: {
				type: Number,
				default: 10,
			},
			// 弹窗内容宽度(当from=left或right时起作用)
			width: {
				type: String,
				default: '60vw',
			},
			// 弹窗内容高度(当from=top或bottom时起作用)
			height: {
				type: String,
				default: '50vh',
			},

			// 显示默认头部标题栏（仅在底部弹出时有）
			showHeader: {
				type: Boolean,
				default: true,
			},
			// 弹窗标题
			title: String,

			// 显示左侧（返回）按钮，如果v-slot:back存在时，也会显示此按钮
			showBack: Boolean,

			// 显示关闭按钮，如果是字符串，将作为uview（需另外引入）的u-icon组件的name（如showClose="close"，会显示close图标）
			showClose: {
				type: [Boolean, String],
				default: true,
			},

			// 是否可点击模态背景关闭弹窗
			maskClick: {
				type: Boolean,
				default: true,
			},
		},
		emits: ['close'],
		data() {
			return {
				scrollTop: 0,
				panStyle: '',
				showPopup: false,
			}
		},
		computed: {
			closeIcon() {
				if (typeof this.showClose == 'string') return this.showClose
				return false
			},
			isVertical() {
				return ['bottom', 'top'].includes(this.from)
			},
			conStyle() {
				let style = this.panStyle || ''
				let r = this.round
				if (r > 0) {
					r += 'px'
					if (this.from == 'bottom') r = [r, r, 0, 0]
					else if (this.from == 'left') r = [0, r, r, 0]
					else if (this.from == 'right') r = [r, 0, 0, r]
					else r = [0, 0, r, r]
					style += `border-radius: ${r.join(' ')};`
				}
				return style
			},
		},
		watch: {
			value(val) {
				if (val == this.showPopup) return
				if (val) this.open()
				else this.close()
			},
			showPopup(val) {
				this.$emit('input', val)
			},
		},
		mounted() {
			if (this.value) this.open()
		},
		methods: {
			onScroll(e) {
				this.scrollTop = e.detail.scrollTop
			},
			onTouch(ev) {
				// if(!this.maskClick) return
				const {
					pageX,
					pageY
				} = ev.changedTouches[0] || ev
				if (['touchstart', 'mousedown'].includes(ev.type)) {
					this.startX = pageX
					this.startY = pageY
					this.startTime = ev.timeStamp
				} else {
					if (!this.startTime) return
					const orien = this.isVertical ? 'Y' : 'X'
					let moveDis = pageY - this.startY
					if (this.from == 'left') moveDis = this.startX - pageX
					else if (this.from == 'right') moveDis = pageX - this.startX
					else if (this.from == 'top') moveDis = -moveDis
					if (!this.maskClick) moveDis /= 3
					const duration = (ev.timeStamp - this.startTime)
					const speed = moveDis / duration
					if (['touchend', 'mouseup'].includes(ev.type)) {
						if (this.panStyle) {
							if (this.maskClick && (moveDis > 120 || speed > 0.25)) {
								this.close()
							} else {
								this.panStyle = `transform: translate${orien}(0); transition: all ease 200ms;`
							}
							setTimeout(() => {
								this.panStyle = ''
							}, 300)
						}
						// conScrollTop = 0
						this.startTime = 0
						return
					}
					// if(this.scrollTop > 0) return

					if (moveDis > 0) {
						if (this.from == 'left' || this.from == 'top') moveDis *= -1
						this.panStyle = `transform: translate${orien}(${moveDis}px); transition: none;`
					}
				}
			},
			onChange({
				show
			}) {
				this.showPopup = show
			},
			open() {
				this.$refs.popup.open()
				this.showPopup = true
			},
			close() {
				this.$refs.popup.close()
				this.showPopup = false
				this.$emit('close')
			},
			onBack() {
				this.$emit('back')
			},
		}
	}
</script>
